/*
    Copyright (C) 2012 Lucas Paradisi, FuDePAN

    This file is part of the FXP project.

    FXP is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    FXP is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with FXP.  If not, see <http://www.gnu.org/licenses/>.


    This is a test file.
*/

#include <gtest/gtest.h>
#include "fx-parser/fxp.h"
#include "mili/mili.h"

using namespace fxp;
using namespace mili;

struct Grupo
{
    struct Supertype
    {
    public:
        std::string name;
        int x;
        int y;
        float z;

        struct PositionData
        {
            size_t pos;
            std::string type;
            bool operator==(const PositionData& o) const
            {
                return (pos == o.pos && type == o.type);
            }
        };

        std::vector<PositionData> LOVpositions;
        std::vector<size_t> positions;


        Supertype(const std::string& name, int x, int y)
            : name(name), x(x), y(y), z(0.0f)
        {}
        void set_z(float value)
        {
            z = value;
        }
        const std::string& get_name() const
        {
            return name;
        }

        void add_position(size_t pos, const std::string& type)
        {
            PositionData pd = { pos, type };
            insert_into(LOVpositions, pd);
        }

        bool operator<(const Supertype& other) const
        {
            return name < other.name;
        }
        bool operator==(const Supertype& o) const
        {
            return (name == o.name && x == o.x && y == o.y && z == o.z && LOVpositions == o.LOVpositions && positions == o.positions);
        }
    };

    std::string name;
    std::vector<Supertype> supertypes;

    bool operator== (const Grupo& g) const
    {
        return (name == g.name && supertypes == g.supertypes);
    }
};

typedef std::vector<Grupo> ExecutionData;


TEST(GeneralTest, withLOVMethod)
{
    ExecutionData original_xd;
    ExecutionData loaded_xd;
    const string notSetString = "NotSet";


    // Loading original values
    const Grupo::Supertype::PositionData pd111 = {1, "X"};
    const Grupo::Supertype::PositionData pd112 = {2, "Y"};
    const Grupo::Supertype::PositionData pd113 = {3, "Z"};
    Grupo::Supertype s11("supertype11", 1, -2);
    s11.set_z(1.23);
    insert_into(s11.LOVpositions, pd111);
    insert_into(s11.LOVpositions, pd112);
    insert_into(s11.LOVpositions, pd113);

    const Grupo::Supertype::PositionData pd121 = {1, "XX"};
    const Grupo::Supertype::PositionData pd122 = {2, "YY"};
    const Grupo::Supertype::PositionData pd123 = {3, "ZZ"};
    Grupo::Supertype s12("supertype12", 2, -2);
    insert_into(s12.LOVpositions, pd121);
    insert_into(s12.LOVpositions, pd122);
    insert_into(s12.LOVpositions, pd123);

    Grupo grupo1;
    grupo1.name = "grupo1";
    insert_into(grupo1.supertypes, s11);
    insert_into(grupo1.supertypes, s12);

    const Grupo::Supertype::PositionData pd211 = {1, "X"};
    const Grupo::Supertype::PositionData pd212 = {2, notSetString};
    const Grupo::Supertype::PositionData pd213 = {3, notSetString};
    Grupo::Supertype s21("supertype21", -1, -2);
    insert_into(s21.LOVpositions, pd211);
    insert_into(s21.LOVpositions, pd212);
    insert_into(s21.LOVpositions, pd213);

    const Grupo::Supertype::PositionData pd221 = {1, notSetString};
    const Grupo::Supertype::PositionData pd222 = {2, notSetString};
    const Grupo::Supertype::PositionData pd223 = {3, notSetString};
    Grupo::Supertype s22("supertype22", -1, -2);
    s22.set_z(3.21);
    insert_into(s22.LOVpositions, pd221);
    insert_into(s22.LOVpositions, pd222);
    insert_into(s22.LOVpositions, pd223);

    Grupo grupo2;
    grupo2.name = "grupo2";
    insert_into(grupo2.supertypes, s21);
    insert_into(grupo2.supertypes, s22);

    insert_into(original_xd, grupo1);
    insert_into(original_xd, grupo2);


    //Loading values with FXP
    FXParserLOVMethod<Grupo::Supertype, void, Parameters2<size_t, const string&> > xmlPositions("position", &Grupo::Supertype::add_position);
    xmlPositions.parameters.set_param0("pos");
    xmlPositions.parameters.set_param1("type", notSetString);

    FXParserNonDef<Grupo::Supertype, Constructor3<Grupo::Supertype, std::string, int, int> > xmlSupertype("supertype");
    xmlSupertype.constructor.set_param0("id");
    xmlSupertype.constructor.set_param1("x", -1);
    xmlSupertype.constructor.set_param2_constant(-2);
    add_attr(xmlSupertype, "z", &Grupo::Supertype::set_z);

    add_lov_child(xmlSupertype, xmlPositions);

    FXParser<Grupo> xmlGrupo("grupo");
    add_child(xmlGrupo, &Grupo::supertypes, xmlSupertype);
    add_attr(xmlGrupo, "id", &Grupo::name);

    FXPRootParser<ExecutionData> dataParser("data", xmlGrupo);
    ignore_attr(dataParser, "ignore_me");

    parse_xml("ref/testWithLOV.xml", loaded_xd, dataParser);


    //Comparing
    ASSERT_EQ(original_xd, loaded_xd);

}



TEST(GeneralTest, withoutLOVMethod)
{
    ExecutionData original_xd;
    ExecutionData loaded_xd;


    // Loading original values
    Grupo::Supertype s11("supertype11", 1, -2);
    s11.set_z(1.23);
    insert_into(s11.positions, 2);
    insert_into(s11.positions, 9);
    Grupo::Supertype s12("supertype12", 2, 3);
    insert_into(s12.positions, 2);

    Grupo grupo1;
    grupo1.name = "grupo1";
    insert_into(grupo1.supertypes, s11);
    insert_into(grupo1.supertypes, s12);

    Grupo::Supertype s21("supertype21", -1, -2);
    insert_into(s21.positions, 9);
    Grupo::Supertype s22("supertype22", -1, -2);
    s22.set_z(3.21);
    insert_into(s22.positions, 9);

    Grupo grupo2;
    grupo2.name = "grupo2";
    insert_into(grupo2.supertypes, s21);
    insert_into(grupo2.supertypes, s22);

    insert_into(original_xd, grupo1);
    insert_into(original_xd, grupo2);


    //Loading values with FXP
    FXParserNonDef<Grupo::Supertype, Constructor3<Grupo::Supertype, std::string, int, int> > xmlSupertype("supertype");
    xmlSupertype.constructor.set_param0("id");
    xmlSupertype.constructor.set_param1("x", -1);
    xmlSupertype.constructor.set_param2("y", -2);
    add_attr(xmlSupertype, "z", &Grupo::Supertype::set_z);

    add_lov_child(xmlSupertype, std::string("position"), std::string("pos"), &Grupo::Supertype::positions);

    FXParser<Grupo> xmlGrupo("grupo");
    add_child(xmlGrupo, &Grupo::supertypes, xmlSupertype);
    add_attr(xmlGrupo, "id", &Grupo::name);

    FXPRootParser<ExecutionData> dataParser("data", xmlGrupo);

    parse_xml("ref/testWithoutLOV.xml", loaded_xd, dataParser);


    //Comparing
    ASSERT_EQ(original_xd, loaded_xd);

}
